package com.cloudcross.ssp.web.multiplatform;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cloudcross.ssp.common.Config;
import com.cloudcross.ssp.common.utils.DateUtils;
import com.cloudcross.ssp.common.utils.DoublePreciseCompute;
import com.cloudcross.ssp.service.IAdReportService;
import com.cloudcross.util.SqlServer;

@Component("multiPlatformCounter")
public class MultiPlatformCounter {

    private Logger logger = LogManager.getLogger(getClass());

    @Autowired
    private Config config;
    @Autowired
    private IAdReportService adReportService;

    private static final Integer PARAM_CPM_MODE = 1;
    private static final Integer PARAM_CPC_MODE = 2;

    private static List<AdGroupBasicData> appFinalList = new ArrayList<AdGroupBasicData>();
    private static List<AdGroupBasicData> pcFinalList = new ArrayList<AdGroupBasicData>();
    private static List<AdGroupOrderVo> groupOrder = new ArrayList<AdGroupOrderVo>();

    private static String yesterday = new String("");

    private static SqlServer manageServer = null;

    private static SqlServer appServer = null;

    private void clearData() {
        appFinalList = new ArrayList<AdGroupBasicData>();
        pcFinalList = new ArrayList<AdGroupBasicData>();
        groupOrder = new ArrayList<AdGroupOrderVo>();
        yesterday = new String("");
        manageServer = null;
        appServer = null;
    }

    private void initData(String yesterday) {
        appFinalList = adReportService.queryAppBasicData(yesterday);
        pcFinalList = adReportService.queryPcBasicData(yesterday);
        groupOrder = adReportService.queryGroupOrderParam();
    }

    private Boolean initDatabaConnect() {
        if (config.getManageHost() == null || config.getManagePort() == null || config.getManageUser() == null || config.getManagePass() == null
                || config.getManageDbname() == null) {
            logger.info("manage database config is error");
            return false;
        }
        if (config.getAppHost() == null || config.getAppPort() == null || config.getAppUser() == null || config.getAppPass() == null
                || config.getAppDbname() == null) {
            logger.info("app database config is error");
            return false;
        }
        manageServer = new SqlServer(config.getManageHost(), Integer.parseInt(config.getManagePort()), config.getManageUser(), config.getManagePass(),
                config.getManageDbname(), 0);
        appServer = new SqlServer(config.getAppHost(), Integer.parseInt(config.getAppPort()), config.getAppUser(), config.getAppPass(),
                config.getAppDbname(), 0);
        return true;
    }

    private void caculate() {
        double appMediaRevenue = new Double(0.0d);
        double pcMediaRevenue = new Double(0.0d);
        // caculate app revenue
        for (int i = 0; i < appFinalList.size(); i++) {
            AdGroupBasicData appBasicData = appFinalList.get(i);
            for (int j = 0; j < groupOrder.size(); j++) {
                AdGroupOrderVo adGroupOrderVo = groupOrder.get(j);
                if (appBasicData.getAdGroupId().intValue() == adGroupOrderVo.getAdGroupId().intValue()) {
                    float price = adGroupOrderVo.getPrice();
                    float profit = adGroupOrderVo.getProfit();
                    int mode = adGroupOrderVo.getMode();
                    double revenue;
                    if (mode == PARAM_CPM_MODE) {
                        // cpm
                        long impressions = appBasicData.getImpressions();
                        revenue = (double) impressions * price * (1 - profit / 100) / 1000;
                        appMediaRevenue = DoublePreciseCompute.round(revenue, 2);
                    } else if (mode == PARAM_CPC_MODE) {
                        // cpc
                        long clicks = appBasicData.getClicks();
                        revenue = (double) clicks * price * (1 - profit / 100);
                        appMediaRevenue = DoublePreciseCompute.round(revenue, 2);
                    }
                    appBasicData.setRevenue(appMediaRevenue);
                }
            }
        }
        // caculate pc revenue
        for (int i = 0; i < pcFinalList.size(); i++) {
            AdGroupBasicData pcBasicData = pcFinalList.get(i);
            for (int j = 0; j < groupOrder.size(); j++) {
                AdGroupOrderVo adGroupOrderVo = groupOrder.get(j);
                if (pcBasicData.getAdGroupId().intValue() == adGroupOrderVo.getAdGroupId().intValue()) {
                    float price = adGroupOrderVo.getPrice();
                    float profit = adGroupOrderVo.getProfit();
                    int mode = adGroupOrderVo.getMode();
                    double revenue;
                    if (mode == PARAM_CPM_MODE) {
                        // cpm
                        long impressions = pcBasicData.getImpressions();
                        revenue = (double) impressions * price * (1 - profit / 100) / 1000;
                        pcMediaRevenue = DoublePreciseCompute.round(revenue, 2);
                    } else if (mode == PARAM_CPC_MODE) {
                        // cpc
                        long clicks = pcBasicData.getClicks();
                        revenue = (double) clicks * price * (1 - profit / 100);
                        pcMediaRevenue = DoublePreciseCompute.round(revenue, 2);
                    }
                    pcBasicData.setRevenue(pcMediaRevenue);
                }
            }
        }
    }

    private void summarDuplicateAdidData() {
        for (int i = 0; i < pcFinalList.size() - 1; i++) {
            AdGroupBasicData summarData = pcFinalList.get(i);
            for (int j = pcFinalList.size() - 1; j > i; j--) {
                if (pcFinalList.get(j).getAdid().equals(pcFinalList.get(i).getAdid())) {
                    AdGroupBasicData temp = pcFinalList.get(j);
                    summarData.setClicks(summarData.getClicks() + temp.getClicks());
                    summarData.setImpressions(summarData.getImpressions() + temp.getImpressions());
                    summarData.setRevenue(summarData.getRevenue() + temp.getRevenue());
                    pcFinalList.remove(j);
                }
            }
        }

        for (int i = 0; i < appFinalList.size() - 1; i++) {
            AdGroupBasicData summarData = appFinalList.get(i);
            for (int j = appFinalList.size() - 1; j > i; j--) {
                if (appFinalList.get(j).getAdid().equals(appFinalList.get(i).getAdid())) {
                    AdGroupBasicData temp = appFinalList.get(j);
                    summarData.setClicks(summarData.getClicks() + temp.getClicks());
                    summarData.setImpressions(summarData.getImpressions() + temp.getImpressions());
                    summarData.setRevenue(summarData.getRevenue() + temp.getRevenue());
                    appFinalList.remove(j);
                }
            }
        }
    }

    private void generateSQL(AdGroupBasicData basicData, boolean flag) {
        if (flag) {
            // pc端
            StringBuilder pcSql = new StringBuilder("");
            pcSql.append("insert into report_daily_channel_data (date,adid,platformname,line,impressions,clicks,revenue) values(");
            pcSql.append("'").append(yesterday).append("',");
            pcSql.append("'").append(basicData.getAdid()).append("',");
            pcSql.append("'db',");
            pcSql.append("1,");
            pcSql.append(basicData.getImpressions()).append(",");
            pcSql.append(basicData.getClicks()).append(",");
            pcSql.append(basicData.getRevenue());
            pcSql.append(") ON DUPLICATE KEY UPDATE impressions=").append(basicData.getImpressions()).append(", clicks = ")
                    .append(basicData.getClicks()).append(", revenue = ").append(basicData.getRevenue() + ";");
            logger.info(pcSql.toString());
            manageServer.execute(pcSql.toString());
        } else {
            // app端
            StringBuilder appSql = new StringBuilder("");
            appSql.append("insert into report_daily_channel_data (date,adid,platformname,line,impressions,clicks,revenue) values(");
            appSql.append("'").append(yesterday).append("',");
            appSql.append("'").append(basicData.getAdid()).append("',");
            appSql.append("'adsp',");
            appSql.append("2,");
            appSql.append(basicData.getImpressions()).append(",");
            appSql.append(basicData.getClicks()).append(",");
            appSql.append(basicData.getRevenue());
            appSql.append(") ON DUPLICATE KEY UPDATE impressions=").append(basicData.getImpressions()).append(", clicks = ")
                    .append(basicData.getClicks()).append(", revenue = ").append(basicData.getRevenue() + ";");
            logger.info(appSql.toString());
            appServer.execute(appSql.toString());
        }

    }

    private void insertPlatform() {
        if (pcFinalList.size() == 0) {
            logger.info("pc data is empty");
        } else {
            for (AdGroupBasicData appBasicData : pcFinalList) {
                generateSQL(appBasicData, true);
            }
        }
        if (appFinalList.size() == 0) {
            logger.info("app data is empty");
        } else {
            for (AdGroupBasicData appBasicData : appFinalList) {
                generateSQL(appBasicData, false);
            }
        }
    }

    private void closeDatabaConnect() {
        manageServer.over();
        appServer.over();
    }

    public void statistics() throws SQLException {
        logger.info("clear static variable to empty");
        clearData();
        logger.info("clear static variable successfully");
        logger.info("start to init database connect");
        boolean isConnect = initDatabaConnect();
        if (!isConnect)
            return;
        logger.info("init database connect end");
        Date yesterdayDate = DateUtils.addDay(new Date(), -1);
        yesterday = DateUtils.getDateToString(DateUtils.DATEFORMATSHORT, yesterdayDate);
        logger.info("start to get group and order param");
        initData(yesterday);
        logger.info("get group and order param successfully");
        logger.info("start to caculate every adid revenue");
        caculate();
        logger.info("caculate every adid revenue end");
        logger.info("caculate every adid revenue successfully");
        summarDuplicateAdidData();
        logger.info("start to insert every adid process data");
        insertPlatform();
        logger.info("insert every adid process data successfully");
        closeDatabaConnect();
    }

}
